package loveqq.niceexcel.util;

import loveqq.niceexcel.core.metadata.NumberFormatData;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhongjh@tsintergy.com
 * @date 2022-08-26
 */
public class NumberUtils {
    private static final ThreadLocal<Map<String/*格式*/, DecimalFormat>> DECIMAL_FORMAT_THREAD_LOCAL = new ThreadLocal<>();

    public static String format(Number value, NumberFormatData data) {
        if (data == null) {
            return (value instanceof BigDecimal) ? ((BigDecimal) value).toPlainString() : value.toString();
        }
        DecimalFormat decimalFormat = getCacheDecimalFormat(data.getFormat());
        decimalFormat.setRoundingMode(data.getRoundingMode());
        return decimalFormat.format(value);
    }

    public static BigDecimal parseBigDecimal(String value, NumberFormatData data) throws ParseException {
        if (data == null) {
            return new BigDecimal(value);
        }
        Number num = parse(value, data);
        return (num instanceof BigDecimal) ? (BigDecimal) num : new BigDecimal(num.toString());
    }

    public static Byte parseByte(String value, NumberFormatData data) throws ParseException {
        return (data != null) ? parse(value, data).byteValue() : Byte.parseByte(value);
    }

    public static Short parseShort(String value, NumberFormatData data) throws ParseException {
        return (data != null) ? parse(value, data).shortValue() : Short.parseShort(value);
    }

    public static Integer parseInteger(String value, NumberFormatData data) throws ParseException {
        return (data != null) ? parse(value, data).intValue() : Integer.parseInt(value);
    }

    public static Long parseLong(String value, NumberFormatData data) throws ParseException {
        return (data != null) ? parse(value, data).longValue() : Long.parseLong(value);
    }

    public static Float parseFloat(String value, NumberFormatData data) throws ParseException {
        return (data != null) ? parse(value, data).floatValue() : Float.parseFloat(value);
    }

    public static Double parseDouble(String value, NumberFormatData data) throws ParseException {
        return (data != null) ? parse(value, data).doubleValue() : Double.parseDouble(value);
    }

    private static Number parse(String value, NumberFormatData data) throws ParseException {
        DecimalFormat decimalFormat = getCacheDecimalFormat(data.getFormat());
        decimalFormat.setRoundingMode(data.getRoundingMode());
        decimalFormat.setParseBigDecimal(true);
        return decimalFormat.parse(value);
    }


    private static DecimalFormat getCacheDecimalFormat(String format) {
        Map<String, DecimalFormat> cache = DECIMAL_FORMAT_THREAD_LOCAL.get();
        if (cache == null) {
            cache = new HashMap<>();
            DECIMAL_FORMAT_THREAD_LOCAL.set(cache);
        }
        return cache.computeIfAbsent(format, key -> new DecimalFormat(format));
    }

    public static void removeThreadLocalCache() {
        DECIMAL_FORMAT_THREAD_LOCAL.remove();
    }

}
